return &self->render_node;
}
+/*** GSK_LINEAR_GRADIENT_NODE ***/
+
+typedef struct _GskLinearGradientNode GskLinearGradientNode;
+
+struct _GskLinearGradientNode
+{
+ GskRenderNode render_node;
+
+ graphene_rect_t bounds;
+
+ graphene_point_t start;
+ graphene_point_t end;
+
+ GskColorStop *stops;
+ gsize n_stops;
+};
+
+static void
+gsk_linear_gradient_node_finalize (GskRenderNode *node)
+{
+ GskLinearGradientNode *self = (GskLinearGradientNode *) node;
+
+ g_free (self->stops);
+}
+
+static void
+gsk_linear_gradient_node_make_immutable (GskRenderNode *node)
+{
+}
+
+static void
+gsk_linear_gradient_node_draw (GskRenderNode *node,
+ cairo_t *cr)
+{
+ GskLinearGradientNode *self = (GskLinearGradientNode *) node;
+ cairo_pattern_t *pattern;
+ gsize i;
+
+ pattern = cairo_pattern_create_linear (self->start.x, self->start.y,
+ self->end.x, self->end.y);
+
+ if (gsk_render_node_get_node_type (node) == GSK_REPEATING_LINEAR_GRADIENT_NODE)
+ cairo_pattern_set_extend (pattern, CAIRO_EXTEND_REPEAT);
+
+ for (i = 0; i < self->n_stops; i++)
+ {
+ cairo_pattern_add_color_stop_rgba (pattern,
+ self->stops[i].offset,
+ self->stops[i].color.red,
+ self->stops[i].color.green,
+ self->stops[i].color.blue,
+ self->stops[i].color.alpha);
+ }
+
+ cairo_set_source (cr, pattern);
+ cairo_pattern_destroy (pattern);
+
+ cairo_rectangle (cr,
+ self->bounds.origin.x, self->bounds.origin.y,
+ self->bounds.size.width, self->bounds.size.height);
+ cairo_fill (cr);
+}
+
+static void
+gsk_linear_gradient_node_get_bounds (GskRenderNode *node,
+ graphene_rect_t *bounds)
+{
+ GskLinearGradientNode *self = (GskLinearGradientNode *) node;
+
+ graphene_rect_init_from_rect (bounds, &self->bounds);
+}
+
+static const GskRenderNodeClass GSK_LINEAR_GRADIENT_NODE_CLASS = {
+ GSK_LINEAR_GRADIENT_NODE,
+ sizeof (GskLinearGradientNode),
+ "GskLinearGradientNode",
+ gsk_linear_gradient_node_finalize,
+ gsk_linear_gradient_node_make_immutable,
+ gsk_linear_gradient_node_draw,
+ gsk_linear_gradient_node_get_bounds
+};
+
+static const GskRenderNodeClass GSK_REPEATING_LINEAR_GRADIENT_NODE_CLASS = {
+ GSK_REPEATING_LINEAR_GRADIENT_NODE,
+ sizeof (GskLinearGradientNode),
+ "GskLinearGradientNode",
+ gsk_linear_gradient_node_finalize,
+ gsk_linear_gradient_node_make_immutable,
+ gsk_linear_gradient_node_draw,
+ gsk_linear_gradient_node_get_bounds
+};
+
+/**
+ * gsk_linear_gradient_node_new:
+ * @linear_gradient: the #GskLinearGradient
+ * @bounds: the rectangle to render the linear_gradient into
+ *
+ * Creates a #GskRenderNode that will render the given
+ * @linear_gradient into the area given by @bounds.
+ *
+ * Returns: A new #GskRenderNode
+ *
+ * Since: 3.90
+ */
+GskRenderNode *
+gsk_linear_gradient_node_new (const graphene_rect_t *bounds,
+ const graphene_point_t *start,
+ const graphene_point_t *end,
+ const GskColorStop *color_stops,
+ gsize n_color_stops)
+{
+ GskLinearGradientNode *self;
+
+ g_return_val_if_fail (bounds != NULL, NULL);
+ g_return_val_if_fail (start != NULL, NULL);
+ g_return_val_if_fail (end != NULL, NULL);
+ g_return_val_if_fail (color_stops != NULL, NULL);
+
+ self = (GskLinearGradientNode *) gsk_render_node_new (&GSK_LINEAR_GRADIENT_NODE_CLASS);
+
+ graphene_rect_init_from_rect (&self->bounds, bounds);
+ graphene_point_init_from_point (&self->start, start);
+ graphene_point_init_from_point (&self->end, end);
+
+ self->stops = g_memdup (color_stops, sizeof (GskColorStop) * n_color_stops);
+ self->n_stops = n_color_stops;
+
+ return &self->render_node;
+}
+
+GskRenderNode *
+gsk_repeating_linear_gradient_node_new (const graphene_rect_t *bounds,
+ const graphene_point_t *start,
+ const graphene_point_t *end,
+ const GskColorStop *color_stops,
+ gsize n_color_stops)
+{
+ GskLinearGradientNode *self;
+
+ g_return_val_if_fail (bounds != NULL, NULL);
+ g_return_val_if_fail (start != NULL, NULL);
+ g_return_val_if_fail (end != NULL, NULL);
+ g_return_val_if_fail (color_stops != NULL, NULL);
+
+ self = (GskLinearGradientNode *) gsk_render_node_new (&GSK_REPEATING_LINEAR_GRADIENT_NODE_CLASS);
+
+ graphene_rect_init_from_rect (&self->bounds, bounds);
+ graphene_point_init_from_point (&self->start, start);
+ graphene_point_init_from_point (&self->end, end);
+
+ self->stops = g_memdup (color_stops, sizeof (GskColorStop) * n_color_stops);
+ self->n_stops = n_color_stops;
+
+ return &self->render_node;
+}
+
/*** GSK_TEXTURE_NODE ***/
typedef struct _GskTextureNode GskTextureNode;
}
static void
-gtk_css_image_linear_draw (GtkCssImage *image,
- cairo_t *cr,
- double width,
- double height)
+gtk_css_image_linear_snapshot (GtkCssImage *image,
+ GtkSnapshot *snapshot,
+ double width,
+ double height)
{
GtkCssImageLinear *linear = GTK_CSS_IMAGE_LINEAR (image);
- cairo_pattern_t *pattern;
+ GskColorStop stops[linear->stops->len];
+ GskRenderNode *node;
+ double off_x, off_y; /* snapshot offset */
double angle; /* actual angle of the gradiant line in degrees */
double x, y; /* coordinates of start point */
double length; /* distance in pixels for 100% */
double start, end; /* position of first/last point on gradient line - with gradient line being [0, 1] */
double offset;
int i, last;
+ char *name;
if (linear->side)
{
length = sqrt (x * x + y * y);
gtk_css_image_linear_get_start_end (linear, length, &start, &end);
- pattern = cairo_pattern_create_linear (x * (start - 0.5), y * (start - 0.5),
- x * (end - 0.5), y * (end - 0.5));
- if (linear->repeating)
- cairo_pattern_set_extend (pattern, CAIRO_EXTEND_REPEAT);
- else
- cairo_pattern_set_extend (pattern, CAIRO_EXTEND_PAD);
offset = start;
last = -1;
step = (pos - offset) / (i - last);
for (last = last + 1; last <= i; last++)
{
- const GdkRGBA *rgba;
-
stop = &g_array_index (linear->stops, GtkCssImageLinearColorStop, last);
- rgba = _gtk_css_rgba_value_get_rgba (stop->color);
offset += step;
- cairo_pattern_add_color_stop_rgba (pattern,
- (offset - start) / (end - start),
- rgba->red,
- rgba->green,
- rgba->blue,
- rgba->alpha);
+ stops[last].offset = (offset - start) / (end - start);
+ stops[last].color = *_gtk_css_rgba_value_get_rgba (stop->color);
}
offset = pos;
last = i;
}
- cairo_rectangle (cr, 0, 0, width, height);
- cairo_translate (cr, width / 2, height / 2);
- cairo_set_source (cr, pattern);
- cairo_fill (cr);
+ gtk_snapshot_get_offset (snapshot, &off_x, &off_y);
+
+ if (linear->repeating)
+ {
+ node = gsk_repeating_linear_gradient_node_new (
+ &GRAPHENE_RECT_INIT (off_x, off_y, width, height),
+ &GRAPHENE_POINT_INIT (off_x + width / 2 + x * (start - 0.5), off_y + height / 2 + y * (start - 0.5)),
+ &GRAPHENE_POINT_INIT (off_x + width / 2 + x * (end - 0.5), off_y + height / 2 + y * (end - 0.5)),
+ stops,
+ linear->stops->len);
+ }
+ else
+ {
+ node = gsk_linear_gradient_node_new (
+ &GRAPHENE_RECT_INIT (off_x, off_y, width, height),
+ &GRAPHENE_POINT_INIT (off_x + width / 2 + x * (start - 0.5), off_y + height / 2 + y * (start - 0.5)),
+ &GRAPHENE_POINT_INIT (off_x + width / 2 + x * (end - 0.5), off_y + height / 2 + y * (end - 0.5)),
+ stops,
+ linear->stops->len);
+ }
+ name = g_strdup_printf ("%sLinearGradient<%ustops>", linear->repeating ? "Repeating" : "", linear->stops->len);
+ gsk_render_node_set_name (node, name);
+ g_free (name);
+
+ gtk_snapshot_append_node (snapshot, node);
- cairo_pattern_destroy (pattern);
+ gsk_render_node_unref (node);
}
GtkCssImageClass *image_class = GTK_CSS_IMAGE_CLASS (klass);
GObjectClass *object_class = G_OBJECT_CLASS (klass);
- image_class->draw = gtk_css_image_linear_draw;
+ image_class->snapshot = gtk_css_image_linear_snapshot;
image_class->parse = gtk_css_image_linear_parse;
image_class->print = gtk_css_image_linear_print;
image_class->compute = gtk_css_image_linear_compute;